package com.wave.spring.jpa;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.criteria.*;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


/**
 * Created by lv on 2017/8/27.
 */
public class CustomerSpecs {
    public static  <T> Specification<T> byAuto(final EntityManager entityManager,final T example){
        final Class<T> type= (Class<T>) example.getClass();
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                EntityType<T> entity = entityManager.getMetamodel().entity(type);
                entity.getDeclaredAttributes().forEach(e -> {
                    Object attrValue = getValue(example, e);
                    if (attrValue != null) {
                        if (e.getJavaType() == String.class) {
                            if (!StringUtils.isEmpty(attrValue)) {
                                Path<String> path = root.get(attribute(entity, e.getName(), String.class));
                                predicates.add(cb.like(path, "%" + attrValue + "%"));
                            }
                        } else {
                            Path<?> path = root.get(attribute(entity, e.getName(), attrValue.getClass()));
                            predicates.add(cb.equal(path, attrValue));
                        }
                    }
                });

                return predicates.isEmpty() ? cb.conjunction() : cb.and((Predicate[]) predicates.toArray());
            }
        };


    }

    private static <E,T> SingularAttribute<T,E> attribute(EntityType<T> entity, String name, Class<E> stringClass) {
return entity.getDeclaredSingularAttribute(name,stringClass);
    }

    private static <T> Object getValue(T example, Attribute<T, ?> e) {
        return ReflectionUtils.getField((Field) e.getJavaMember(),example);
    }
}
